﻿using System;
using System.Collections.Generic;


namespace FinQ
{

    /// <summary>
    /// Sam's functional programming library. F'LINQ!
    /// </summary>
    static partial class Functional
    {
        public static IEnumerable<T> NestList<T>(Func<T, T> fn, T start, int N)
        {
            List<T> result = new List<T>();
            T last = start;
            for (int i = 0; i < N; i++)
            {
                result.Add(last);
                last = fn(last);
            }
            result.Add(last);
            return result;
        }

        public static IEnumerable<T> NestWhileList<T>(Func<T, T> fn, T start, Func<T, bool> pred)
        {
            List<T> result = new List<T>();
            T last = start;
            while (pred(last))
            {
                result.Add(last);
                last = fn(last);
            }
            result.Add(last);
            return result;
        }

        public static IEnumerable<T> NestWhileList<T>(Func<T, T> fn, T start, Func<T, bool> pred, int Max)
        {
            List<T> result = new List<T>();
            T last = start;
            int count = 0;
            while (pred(last) && count++ < Max)
            {
                result.Add(last);
                last = fn(last);
            }
            result.Add(last);
            return result;
        }

        public static T Nest<T>(Func<T, T> fn, T start, int N)
        {
            T result = start;
            for (int i = 0; i < N; i++)
                result = fn(result);
            return result;
        }

        public static T NestWhile<T>(Func<T, T> fn, T start, Func<T, bool> pred)
        {
            T result = start;
            while (pred(result))
                result = fn(result);
            return result;
        }

        public static T NestWhile<T>(Func<T, T> fn, T start, Pred<T> pred, int Max)
        {
            T result = start;
            int count = 0;
            while (pred(result) && count++ < Max)
                result = fn(result);
            return result;
        }

        // not functional currently
        public static IEnumerable<T> NestWhileList<T>(Func<T, T> fn, T start, Func<List<T>, bool> pred, int m, int max)
        {
            List<T> result = new List<T>();
            T last = start;
            List<T> predArgs = new List<T>(); //BS setup for first args
            predArgs.Add(last);
            int count = 0;
            while (pred(predArgs) && count++ < max)
            {
                result.Add(last);
                last = fn(last);
                int rangeStart = (m >= count) ? 0 : count - m;
                predArgs = result.GetRange(rangeStart, count - rangeStart);
            }
            result.Add(last);
            return result;
        }
    }
}